home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / CommandNotFound / CommandNotFound.py < prev    next >
Text File  |  2009-10-13  |  10KB  |  225 lines

  1. # (c) Zygmunt Krynicki 2005, 2006, 2007, 2008
  2. # Licensed under GPL, see COPYING for the whole text
  3.  
  4. import sys, os, os.path, gdbm, posix, grp, string
  5. from util import gettext_wrapper as _
  6.  
  7. class BinaryDatabase:
  8.     def __init__(self, filename):
  9.         self.db = None
  10.         if filename.endswith(".db"):
  11.             try:
  12.                 self.db = gdbm.open(filename, "r")
  13.             except gdbm.error, err:
  14.                 print >>sys.stderr, "Unable to open binary database %s: %s" % (filename, err)
  15.     def lookup(self, key):
  16.         if self.db and self.db.has_key(key):
  17.             return self.db[key]
  18.         else:
  19.             return None
  20.  
  21. class FlatDatabase:
  22.     def __init__(self, filename):
  23.         self.rows = []
  24.         dbfile = file(filename)
  25.         for line in (line.strip() for line in dbfile):
  26.             self.rows.append(line.split("|"))
  27.         dbfile.close()
  28.     def lookup(self, column, text):
  29.         result = []
  30.         for row in self.rows:
  31.             if row[column] == text:
  32.                 result.append(row)
  33.         return result
  34.     def createColumnByCallback(self, cb, column):
  35.         for row in self.rows:
  36.             row.append(cb(row[column]))
  37.     def lookupWithCallback(self, column, cb, text):
  38.         result = []
  39.         for row in self.rows:
  40.             if cb(row[column],text):
  41.                 result.append(row)
  42.         return result
  43.  
  44. class ProgramDatabase:
  45.     (PACKAGE, BASENAME_PATH) = range(2)
  46.     def __init__(self, filename):
  47.         basename = os.path.basename(filename)
  48.         (self.arch, self.component) = basename.split(".")[0].split("-")
  49.         self.db = BinaryDatabase(filename)
  50.     def lookup(self, command):
  51.         result = self.db.lookup(command)
  52.         if result:
  53.             return result.split("|")
  54.         else:
  55.             return []
  56.  
  57. def similar_words(word):
  58.     """ return a set with spelling1 distance alternative spellings
  59.  
  60.         based on http://norvig.com/spell-correct.html"""
  61.     alphabet = 'abcdefghijklmnopqrstuvwxyz-_'
  62.     s = [(word[:i], word[i:]) for i in range(len(word) + 1)]
  63.     deletes    = [a + b[1:] for a, b in s if b]
  64.     transposes = [a + b[1] + b[0] + b[2:] for a, b in s if len(b)>1]
  65.     replaces   = [a + c + b[1:] for a, b in s for c in alphabet if b]
  66.     inserts    = [a + c + b     for a, b in s for c in alphabet]
  67.     return set(deletes + transposes + replaces + inserts)
  68.  
  69. class CommandNotFound:
  70.     programs_dir = "programs.d"
  71.     prefixes = ("/bin", 
  72.                 "/usr/bin", 
  73.                 "/usr/local/bin", 
  74.                 "/sbin", "/usr/sbin",
  75.                 "/usr/local/sbin", 
  76.                 "/usr/games")
  77.     def __init__(self, data_dir=os.sep.join(
  78.             ('/','usr','share','command-not-found'))):
  79.         self.programs = []
  80.         self.priority_overrides = []
  81.         p = os.path.join(data_dir, "priority.txt")
  82.         if os.path.exists(p):
  83.             self.priority_overrides = map(string.strip, open(p).readlines())
  84.         self.components = ['main','universe','contrib','restricted','non-free',
  85.                            'multiverse']
  86.         self.components.reverse()
  87.         self.sources_list = self._getSourcesList()
  88.         for filename in os.listdir(os.path.sep.join([data_dir, self.programs_dir])):
  89.             self.programs.append(ProgramDatabase(os.path.sep.join([data_dir, self.programs_dir, filename])))
  90.         try:
  91.             self.user_can_sudo = grp.getgrnam("admin")[2] in posix.getgroups()
  92.         except KeyError:
  93.             self.user_can_sudo = False
  94.  
  95.     def print_spelling_suggestion(self, word, min_len=3, max_len=15):
  96.         " try to correct the spelling "
  97.         if len(word) < min_len:
  98.             return
  99.         possible_alternatives = []
  100.         for w in similar_words(word):
  101.             packages = self.getPackages(w)
  102.             for (package, comp) in packages:
  103.                 possible_alternatives.append((w, package, comp))
  104.         if len(possible_alternatives) > max_len:
  105.             print >>sys.stderr, _("No command '%s' found, but there are %s similar ones") % (word, len(possible_alternatives))
  106.         elif len(possible_alternatives) > 0:
  107.             print >>sys.stderr, _("No command '%s' found, did you mean:") % word
  108.             for (w, p, c) in possible_alternatives:
  109.                 print >>sys.stderr, _(" Command '%s' from package '%s' (%s)") % (w, p, c)
  110.  
  111.     def getPackages(self, command):
  112.         result = set()
  113.         for db in self.programs:
  114.             result.update([(pkg,db.component) for pkg in db.lookup(command)])
  115.         return list(result)
  116.     def getBlacklist(self):
  117.         try:
  118.             blacklist = file(os.sep.join((os.getenv("HOME", "/root"), ".command-not-found.blacklist")))
  119.             return [line.strip() for line in blacklist if line.strip() != ""]
  120.         except IOError:
  121.             return []
  122.         else:
  123.             blacklist.close()
  124.     def _getSourcesList(self):
  125.         try:
  126.             import apt_pkg
  127.             from aptsources.sourceslist import SourcesList
  128.             apt_pkg.init()
  129.         except (SystemError, ImportError), e:
  130.             return []
  131.         sources_list = set([])
  132.         for source in SourcesList():
  133.              if not source.disabled and not source.invalid:
  134.                  for component in source.comps:
  135.                      sources_list.add(component)
  136.         return sources_list
  137.     def sortByComponent(self, x, y):
  138.         # check overrides
  139.         if (x[0] in self.priority_overrides and
  140.             y[0] in self.priority_overrides):
  141.             # both have priority, do normal sorting
  142.             pass
  143.         elif x[0] in self.priority_overrides:
  144.             return -1
  145.         elif y[0] in self.priority_overrides:
  146.             return 1
  147.         # component sorting
  148.         try:
  149.             xidx = self.components.index(x[1])
  150.         except:
  151.             xidx = -1
  152.         try:
  153.             yidx = self.components.index(y[1])
  154.         except:
  155.             xidx = -1
  156.         return (yidx-xidx) or cmp(x,y)
  157.     def advise(self, command, ignore_installed=False):
  158.         " give advice where to find the given command to stderr "
  159.         def _in_prefix(prefix, command):
  160.             " helper that returns if a command is found in the given prefix "
  161.             return (os.path.exists(os.path.join(prefix, command)) and 
  162.                     not os.path.isdir(os.path.join(prefix, command)))
  163.  
  164.         if command.startswith("/"):
  165.             if os.path.exists(command):
  166.                 prefixes = [os.path.dirname(command)]
  167.             else:
  168.                 prefixes = []
  169.         else:
  170.             prefixes = [prefix for prefix in self.prefixes if _in_prefix(prefix, command)]
  171.  
  172.         # check if we have it in a common prefix that may not be in the PATH
  173.         if prefixes and not ignore_installed:
  174.             if len(prefixes) == 1:
  175.                 print >>sys.stderr, _("Command '%(command)s' is available in '%(place)s'") % {"command": command, "place": os.path.join(prefixes[0], command)}
  176.             else:
  177.                 print >>sys.stderr, _("Command '%(command)s' is available in the following places") % {"command": command}
  178.                 for prefix in prefixes:
  179.                     print >>sys.stderr, " * %s" % os.path.join(prefix, command)
  180.             missing = list(set(prefixes) - set(os.getenv("PATH", "").split(":")))
  181.             if len(missing) > 0:
  182.                 print >>sys.stderr, _("The command could not be located because '%s' is not included in the PATH environment variable.") % ":".join(missing)
  183.                 if "sbin" in ":".join(missing):
  184.                     print >>sys.stderr, _("This is most likely caused by the lack of administrative priviledges associated with your user account.")
  185.             return False
  186.  
  187.         # do not give advice if we are in a situation where apt-get
  188.         # or aptitude are not available (LP: #394843)
  189.         if not (os.path.exists("/usr/bin/apt-get") or
  190.                 os.path.exists("/usr/bin/aptitude")):
  191.             return False
  192.  
  193.         if command in self.getBlacklist():
  194.             return False
  195.         packages = self.getPackages(command)
  196.         if len(packages) == 0:
  197.             self.print_spelling_suggestion(command)
  198.         elif len(packages) == 1:
  199.             print >>sys.stderr, _("The program '%s' is currently not installed. ") % command,
  200.             if posix.geteuid() == 0:
  201.                 print >>sys.stderr, _("You can install it by typing:")
  202.                 print >>sys.stderr, "apt-get install %s" %  packages[0][0]
  203.             elif self.user_can_sudo:
  204.                 print >>sys.stderr, _("You can install it by typing:")
  205.                 print >>sys.stderr, "sudo apt-get install %s" %  packages[0][0]
  206.             else:
  207.                 print >>sys.stderr, _("To run '%(command)s' please ask your administrator to install the package '%(package)s'") % {'command': command, 'package': packages[0][0]}
  208.             if not packages[0][1] in self.sources_list:
  209.                 print >>sys.stderr, _("You will have to enable the component called '%s'") % packages[0][1]
  210.         elif len(packages) > 1:
  211.             packages.sort(self.sortByComponent)
  212.             print >>sys.stderr, _("The program '%s' can be found in the following packages:") % command
  213.             for package in packages:
  214.                 if package[1] in self.sources_list:
  215.                     print >>sys.stderr, " * %s" % package[0]
  216.                 else:
  217.                     print >>sys.stderr, " * %s" % package[0] + " (" + _("You will have to enable component called '%s'") % package[1] + ")"
  218.             if posix.geteuid() == 0:
  219.                 print >>sys.stderr, _("Try: %s <selected package>") % "apt-get install"
  220.             elif self.user_can_sudo:
  221.                 print >>sys.stderr, _("Try: %s <selected package>") % "sudo apt-get install"
  222.             else:
  223.                 print >>sys.stderr, _("Ask your administrator to install one of them")
  224.         return len(packages) > 0
  225.